﻿Imports Microsoft.DirectX

Namespace Actor

    Friend Class MirActor

        Dim objAnimLock As New Object

        Public Structure HitIndicator
            Dim val As Integer
            Dim xoff As Integer
            Dim yoff As Integer
            Dim movtick As Long
        End Structure

        Public ActorID As Integer
        Public ActorName As String
        Public ActorLevel As Integer
        Public ActorJob As EvoLib.Protocol.CharacterJobs
        Public ActorSex As EvoLib.Protocol.Gender
        Public ShapeInfo As EvoLib.Protocol.ShapeInfo
        Public ActorType As EvoLib.Protocol.PlayerType
        Public VitalPoints As EvoLib.Protocol.Vitals
        Public IsDead As Boolean
        Public Stats As EvoLib.Protocol.StatsSet
        Public Weights As PlayerWeights

        Public WithEvents mHumAnim As GUI.MirAnimation
        Public WithEvents mHeadAnim As GUI.MirAnimation
        Public WithEvents mWeaponAnim As GUI.MirAnimation

        Public mChatText As String
        Public mChatTimeout As Long

        Public Structure ActorAction
            Dim humanim As EvoLib.Protocol.HUMAnimation
            Dim dir As EvoLib.Protocol.Direction
            Dim magiccode As EvoLib.Protocol.Magics
            Dim startpos As EvoLib.Protocol.PlayerPositionInfo
        End Structure

        Public ActionQueue As List(Of ActorAction)
        Private LastAction As ActorAction

        Private isRunning As Boolean
        Private hasWalkedBeforeRun As Boolean
        Private hasRun As Boolean

        Private isWalking As Boolean

        Private isStanding As Boolean

        Private isAttacking As Boolean
        Private attackingCooldown As Long

        Private isGettingHit As Boolean

        Private isCasting1 As Boolean
        Private castingCooldown As Long

        Private isAnimSet As Boolean

        Public AvoidingCollision As Boolean

        Public currentanim As EvoLib.Protocol.HUMAnimation
        Public currentstaticdirection As EvoLib.Protocol.Direction
        Private currentmovementdirection As EvoLib.Protocol.Direction
        Private currentpointerdirection As EvoLib.Protocol.Direction
        Public actualdirection As EvoLib.Protocol.Direction

        Private currentmovementtick As Long
        Private currentmovementtimer As Long
        Private currentmovementdistx As Single
        Private currentmovementdisty As Single

        Private startframe As Integer

        Private hasmoved As Boolean
        Private isstopping As Boolean

        Private lastxcoord As Integer
        Private lastycoord As Integer

        Public lstHits As New List(Of Player.HitIndicator)

        Private mStepsToGo As Integer

        Public ActorTexture As Direct3D.Texture
        Public ActorSurface As Direct3D.Surface

        Public Enum TargetType
            Mob = 0
        End Enum

        Public mTargetType As TargetType
        Public mTargetID As Integer
        Public mTargeting As Boolean
        Private mAttackTargetMelee As Boolean



        Public mXCoord As Integer
        Public mYCoord As Integer


        Public MovementOffsetX As Double, MovementOffsetY As Double


        Public Sub New(ByVal id As Int64, ByVal pinfo As EvoLib.Protocol.PlayerInfo, ByVal posinfo As EvoLib.Protocol.PlayerPositionInfo, ByVal vp As EvoLib.Protocol.Vitals)

            actualdirection = posinfo.BYTE_DIRECTION
            currentstaticdirection = posinfo.BYTE_DIRECTION
            ActorID = id
            ActorName = pinfo.STR_NAME
            ActorSex = pinfo.BYTE_GENDER
            ShapeInfo = pinfo.ShapeInfo
            mXCoord = posinfo.INT2_X
            mYCoord = posinfo.INT2_Y
            VitalPoints = vp
            ActorType = pinfo.TYPE

            ActorTexture = New Direct3D.Texture(DirectX.D3D, DirectX.DispMode.Width, DirectX.DispMode.Height, 1, Microsoft.DirectX.Direct3D.Usage.RenderTarget, DirectX.ColorFormat, Microsoft.DirectX.Direct3D.Pool.Default)
            ActorSurface = ActorTexture.GetSurfaceLevel(0)

            mHumAnim = New GUI.MirAnimation(GameWindow.GameWin, "mHumAnim" & id, 0, 0, True)
            'mHumAnim.Visible = False
            mHeadAnim = New GUI.MirAnimation(GameWindow.GameWin, "mHeadAnim" & id, 0, 0, True)
            'mHeadAnim.Visible = False
            mWeaponAnim = New GUI.MirAnimation(GameWindow.GameWin, "mWeaponAnim" & id, 0, 0, True)
            'mWeaponAnim.Visible = False

            ActionQueue = New List(Of ActorAction)

            ChangeStaticDirection(EvoLib.Protocol.Direction.S)
            Dim info As PlayerPositionInfo
            info.INT2_X = mXCoord
            info.INT2_Y = mYCoord
            Stand(info)
            CalcAnim()

        End Sub

        Public Sub DrawMain(ByRef mode As Globals.DrawingMode, ByRef offsetX As Integer, ByRef offsetY As Integer, ByRef originX As Integer, ByRef originY As Integer, ByRef defaultZ As Single)

            If mode = Globals.DrawingMode.Normal Then

                Dim z As Single
                Dim dx As Integer
                Dim dy As Integer

                dx = offsetX + ((mXCoord - originX) * Constants.TileWidth) - MovementOffsetX
                dy = offsetY + ((mYCoord - originY) * Constants.TileHeight) - MovementOffsetY
                z = (defaultZ - ((mYCoord - originY) * 0.005F)) - 0.003F

                DirectX.BlitD3D(ActorTexture, 0, 0, Constants.gGameResX, Constants.gGameResY, 0.5F)
            End If

        End Sub

        Public Sub DrawShadow(ByVal mode As Globals.DrawingMode, ByRef offsetX As Integer, ByRef offsetY As Integer, ByRef originX As Integer, ByRef originY As Integer, ByRef defaultZ As Single)

            If mode = Globals.DrawingMode.Shadow Then

                Dim z As Single
                Dim dx As Integer
                Dim dy As Integer

                dx = offsetX + ((mXCoord - originX) * Constants.TileWidth) - MovementOffsetX
                dy = offsetY + ((mYCoord - originY) * Constants.TileHeight) - MovementOffsetY
                z = (defaultZ - ((mYCoord - originY) * 0.01))


                DirectX.GameSprite.Begin(Microsoft.DirectX.Direct3D.SpriteFlags.AlphaBlend)
                Engine.SetDrawModeShadow(Globals.ShadowBlend)

                DirectX.GameSprite.Transform = Microsoft.DirectX.Matrix.Transformation(New Microsoft.DirectX.Vector3(dx, dy, 0.0F), Microsoft.DirectX.Quaternion.Identity, New Microsoft.DirectX.Vector3(1.2F, 1.0F, 1.0F), New Microsoft.DirectX.Vector3(dx, dy, z), New Microsoft.DirectX.Quaternion(-0.7F, 0.4F, 0.0F, 0.0F), New Microsoft.DirectX.Vector3(15.0F, 15.0F, 0.0F))
                DirectX.GameSprite.Draw(ActorTexture, New Rectangle(0, 0, Constants.gGameResX, Constants.gGameResY), New Microsoft.DirectX.Vector3(0.0F, 0.0F, 0.0F), New Microsoft.DirectX.Vector3(0.0F, 0.0F, z), Color.White)

                DirectX.GameSprite.End()

                DirectX.GameSprite.Transform = Microsoft.DirectX.Matrix.Identity
            End If

        End Sub

        Public Sub DrawOverlay(ByRef offsetX As Integer, ByRef offsetY As Integer, ByRef originX As Integer, ByRef originY As Integer, ByRef defaultZ As Single)

            DirectX.D3D.SetRenderTarget(0, ActorSurface)
            'Begin D3D scene
            DirectX.D3D.BeginScene()
            'Clear target and z-buffer
            DirectX.D3D.Clear(Microsoft.DirectX.Direct3D.ClearFlags.Target Or Microsoft.DirectX.Direct3D.ClearFlags.ZBuffer, Color.Transparent, 1.0F, 0)


            'Begin GameSprite rendering
            DirectX.GameSprite.Begin(Microsoft.DirectX.Direct3D.SpriteFlags.AlphaBlend)
            'Set draw mode to plain
            Engine.SetDrawModeNormal(1.0, Color.White)

            'Draw the player... in normal mode
            DrawActor(Globals.DrawingMode.Normal, offsetX, offsetY, originX, originY, defaultZ)

            'End GameSprite rendering
            DirectX.GameSprite.End()

            DirectX.GameSprite.Begin(Microsoft.DirectX.Direct3D.SpriteFlags.AlphaBlend)
            Engine.SetDrawModeMagic(1.0F, Color.White)
            DrawActor(Globals.DrawingMode.Magic, offsetX, offsetY, originX, originY, defaultZ)
            DirectX.GameSprite.End()

            'Set draw mode to tinted, ready to draw Alpha channels
            Engine.SetDrawModeTinted(1.0, Color.White)
            'Draw any tinted sections of the player
            DrawActor(Globals.DrawingMode.Tinted, offsetX, offsetY, originX, originY, defaultZ)

            Engine.SetDrawModeNormal(1.0, Color.White)
            DrawActor(Globals.DrawingMode.Text, offsetX, offsetY, originX, originY, defaultZ)

            'End the D3D scene
            DirectX.D3D.EndScene()

        End Sub

        Public Sub DrawActor(mode As Globals.DrawingMode, ByRef offsetX As Integer, ByRef offsetY As Integer, ByRef originX As Integer, ByRef originY As Integer, ByRef defaultZ As Single)

            Dim dx As Integer
            Dim dy As Integer
            Dim z As Single

            With Me 'tmpChar

                dx = offsetX + ((mXCoord - originX) * Constants.TileWidth) - MovementOffsetX
                dy = offsetY + ((mYCoord - originY) * Constants.TileHeight) - MovementOffsetY
                z = (defaultZ - ((mYCoord - originY) * 0.01))

                If mode = Globals.DrawingMode.Normal Or mode = Globals.DrawingMode.Tinted Or mode = Globals.DrawingMode.Text Or mode = Globals.DrawingMode.Magic Then

                    If mode = Globals.DrawingMode.Normal Or mode = Globals.DrawingMode.Tinted Then

                        'Main HUM Animation
                        '.mHumAnim.Visible = True
                        '.mHumAnim.Draw(mode, dx, dy, z)
                        .mHumAnim.SetPos(dx, dy)
                        .mHumAnim.Draw(mode, 0, 0, z - 0.01F)
                        '.mHumAnim.Visible = False

                        'Head Animation (helmet / hair)
                        .mHeadAnim.Visible = True
                        .mHeadAnim.Draw(mode, dx, dy, z - 0.02F)
                        '.mHeadAnim.SetPos(dx, dy)
                        '.mHeadAnim.Draw(mode, 0, 0, z - 0.02F)
                        .mHeadAnim.Visible = False

                    End If

                    If mode = Globals.DrawingMode.Normal Then

                        'Hit indicators.
                        DrawHitIndicators(lstHits, dx, dy)

                        'Draw HP bar
                        If .VitalPoints.HP > 0 Then
                            Game.DrawVitalsBar(offsetX + ((.mXCoord - originX) * Constants.TileWidth) - .MovementOffsetX, offsetY + ((.mYCoord - originY) * Constants.TileHeight) - .MovementOffsetY, .VitalPoints, Game.VitalsStyle.HUM_HP_Only)
                        End If

                        'Head Animation (helmet / hair)
                        '.mHeadAnim.Visible = True
                        '.mHeadAnim.Draw(mode, dx, dy, z)
                        '.mHeadAnim.SetPos(dx, dy)
                        '.mHeadAnim.Visible = False


                        'calculate weapon Z offset
                        Dim weapz As Single
                        Select Case .actualdirection
                            Case EvoLib.Protocol.Direction.N
                                weapz = 0.01
                            Case EvoLib.Protocol.Direction.NE
                                weapz = -0.01
                            Case EvoLib.Protocol.Direction.E
                                weapz = -0.01
                            Case EvoLib.Protocol.Direction.SE
                                weapz = -0.01
                            Case EvoLib.Protocol.Direction.S
                                weapz = -0.01
                            Case EvoLib.Protocol.Direction.SW
                                weapz = 0.01
                            Case EvoLib.Protocol.Direction.W
                                weapz = 0.01
                            Case EvoLib.Protocol.Direction.NW
                                weapz = 0.01
                        End Select

                        'Weapon Animation
                        '.mWeaponAnim.Visible = True
                        .mWeaponAnim.SetPos(dx, dy)
                        .mWeaponAnim.Draw(mode, 0, 0, (z + weapz) - 0.005F)
                        '.mWeaponAnim.Visible = False

                    ElseIf mode = Globals.DrawingMode.Magic Then

                        Player.DrawPlayerTypeHeader(ActorType, dx, dy)

                    End If

                    If mode = Globals.DrawingMode.Text Then

                        'Chat Message
                        'Chjeck if chat message should be drawn atm
                        If .mChatTimeout > DateTime.Now.Ticks Then

                            'Draw chat message

                            'Chat Message Pos
                            'dx + (Constants.TileWidth \ 2) - (.mChatMessage.Width \ 2), dy - CInt(Constants.TileHeight * 2.4F)

                            'compute text position and size
                            Dim tW As Integer = DirectX.ProFont9.GetNormalTextWidth(.mChatText)
                            If tW >= Constants.ChatMessageWidth Then tW = Constants.ChatMessageWidth
                            Dim tH As Integer = DirectX.ProFont9.GetNormalTextHeight(.mChatText, tW)
                            Dim tX As Integer = (dx + (Constants.TileWidth \ 2)) - (tW \ 2)
                            Dim tY As Integer = dy - CInt(CSng(Constants.TileHeight) * 2.4F)

                            'destination rectangle
                            Dim Dest As Rectangle = New Rectangle(tX, tY, tW, tH + Constants.TileHeight)
                            'DrawTextFormat flags
                            Dim fmt As Microsoft.DirectX.Direct3D.DrawTextFormat = Microsoft.DirectX.Direct3D.DrawTextFormat.Center Or _
                                                        Microsoft.DirectX.Direct3D.DrawTextFormat.ExpandTabs Or _
                                                        Microsoft.DirectX.Direct3D.DrawTextFormat.WordBreak Or _
                                                        Microsoft.DirectX.Direct3D.DrawTextFormat.NoClip
                            'draw chat text
                            DirectX.ProFont9.DrawBorderTextEx(.mChatText, Dest, fmt, Color.White, Color.Black, Constants.GameTextZ)

                        Else

                            'reset timeout to 0 now that it has already expired
                            .mChatTimeout = 0

                        End If

                        'Name Text
                        'Check if the mouse is over this characters tile/position
                        If GameWindow.MouseX = .mXCoord And GameWindow.MouseY = .mYCoord Then

                            'Mouse is over this Character

                            'Name Text Pos
                            'dx + (Constants.TileWidth \ 2) - (.mNameText.Width \ 2), dy - Constants.TileHeight
                            'calculate 'Name Text' width
                            Dim tW As Integer = DirectX.ProFont9.GetNormalTextWidth(.ActorName)
                            'Draw 'Name Text'
                            DirectX.ProFont9.DrawBorderTextEx(.ActorName, dx + (Constants.TileWidth \ 2) - (tW \ 2), dy - Constants.TileHeight, Color.White, Color.Black, Constants.GameTextZ)

                        End If

                    End If

                End If

            End With

        End Sub

        Public Sub SetPos(ByRef posinfo As EvoLib.Protocol.PositionInfo)
            mXCoord = posinfo.INT2_X
            mYCoord = posinfo.INT2_Y
        End Sub

        Private Sub ResetAnimBools()
            isStanding = False
            isWalking = False
            isRunning = False
            isAnimSet = False
            startframe = 0
            hasWalkedBeforeRun = False
            hasRun = False
            hasmoved = False
            isstopping = False
            isCasting1 = False
            isAttacking = False
            isGettingHit = False
        End Sub

        Public Sub Run(ByRef info As EvoLib.Protocol.PlayerPositionInfo)

            SyncLock objAnimLock

                If Not IsDead Then

                    ClearMovements()
                    ClearAttacks()

                    Dim tmp As ActorAction
                    tmp.dir = currentstaticdirection
                    tmp.humanim = EvoLib.Protocol.HUMAnimation.Running
                    tmp.startpos = info

                    ActionQueue.Add(tmp)

                    hasWalkedBeforeRun = False

                    mStepsToGo += 1

                End If

            End SyncLock

        End Sub

        Public Sub Walk(ByRef info As EvoLib.Protocol.PlayerPositionInfo)

            SyncLock objAnimLock

                If Not IsDead Then

                    ClearMovements()
                    ClearAttacks()

                    Dim tmp As ActorAction
                    tmp.dir = currentstaticdirection
                    tmp.humanim = EvoLib.Protocol.HUMAnimation.Walking
                    tmp.startpos = info

                    ActionQueue.Add(tmp)

                    mStepsToGo += 1

                End If

            End SyncLock

        End Sub

        Public Sub Cast1(ByRef info As EvoLib.Protocol.PlayerPositionInfo)

            SyncLock objAnimLock

                'check we're not dead
                If Not IsDead Then

                    'check the cooldown
                    If castingCooldown < DateTime.Now.Ticks Then

                        'clear any movement in the action queue
                        ClearMovements()
                        'clear any attacks in the action queue
                        ClearAttacks()

                        'add cast action for this magic to the action queue
                        Dim tmp As ActorAction
                        tmp.dir = currentpointerdirection
                        tmp.humanim = EvoLib.Protocol.HUMAnimation.Cast1
                        tmp.startpos = info
                        ActionQueue.Add(tmp)

                        'make the player stand after casting
                        Stand(info)
                        'delete any duplicate throwing cast actions
                        DeleteExcessActions(EvoLib.Protocol.HUMAnimation.Cast1)

                        'set the cool down period
                        castingCooldown = DateTime.Now.Ticks + 15000000 'TODO:Set different cool downs for individual magics

                    End If

                End If

            End SyncLock

        End Sub

        Public Sub Attack(ByRef info As EvoLib.Protocol.PlayerPositionInfo)

            If isGettingHit Then Exit Sub

            SyncLock objAnimLock

                If Not IsDead Then

                    If attackingCooldown < DateTime.Now.Ticks Then

                        'ClearMovements()
                        'ClearAttacks()

                        Dim tmp As ActorAction
                        tmp.dir = currentstaticdirection
                        tmp.humanim = EvoLib.Protocol.HUMAnimation.Attack
                        tmp.startpos = info

                        ActionQueue.Add(tmp)

                        attackingCooldown = DateTime.Now.Ticks + 10000000


                        DeleteExcessActions(EvoLib.Protocol.HUMAnimation.Attack)

                        Stand(info)

                    End If

                End If

            End SyncLock

        End Sub

        Public Sub Hit(ByRef info As EvoLib.Protocol.PlayerPositionInfo)

            SyncLock objAnimLock

                If Not IsDead Then

                    Try

                        'ClearMovements()
                        'ClearAttacks()

                        Dim tmp As ActorAction

                        tmp.dir = actualdirection
                        tmp.humanim = EvoLib.Protocol.HUMAnimation.GettingHit
                        tmp.startpos = info

                        ActionQueue.Insert(0, tmp)
                        DeleteExcessActions(EvoLib.Protocol.HUMAnimation.GettingHit)

                        isGettingHit = True

                    Catch
                        Debug.Print("Error in Actor Hit()")
                    End Try

                    Me.MovementOffsetX = 0
                    Me.MovementOffsetY = 0
                    Stand(info)

                End If

            End SyncLock

        End Sub

        Public Sub Die(ByRef info As EvoLib.Protocol.PlayerPositionInfo)

            SyncLock objAnimLock

                mTargeting = False
                IsDead = True
                isGettingHit = False

                Dim tmp As ActorAction
                tmp.startpos = info
                tmp.dir = actualdirection
                tmp.humanim = EvoLib.Protocol.HUMAnimation.Die

                ActionQueue.Clear()

                ActionQueue.Add(tmp)

            End SyncLock

        End Sub

        Public Sub Stand()

            SyncLock objAnimLock

                If Not IsDead Then

                    isGettingHit = False

                    ActionQueue.Clear()

                    Dim tmp As ActorAction
                    tmp.startpos.INT2_X = mXCoord
                    tmp.startpos.INT2_Y = mYCoord
                    tmp.dir = currentstaticdirection
                    tmp.humanim = EvoLib.Protocol.HUMAnimation.Standing
                    'tmp.startpos = info

                    ActionQueue.Add(tmp)
                    DeleteExcessActions(HUMAnimation.Standing)

                End If

            End SyncLock

        End Sub

        Public Sub Stand(ByRef info As EvoLib.Protocol.PlayerPositionInfo)

            SyncLock objAnimLock

                If Not IsDead Then

                    isGettingHit = False

                    ClearMovements()

                    Dim tmp As ActorAction
                    tmp.startpos = info
                    tmp.dir = currentstaticdirection
                    tmp.humanim = EvoLib.Protocol.HUMAnimation.Standing
                    'tmp.startpos = info

                    ActionQueue.Add(tmp)
                    DeleteExcessActions(HUMAnimation.Standing)

                End If

            End SyncLock

        End Sub

        Private Sub ClearMovements()

            If ActionQueue.Count = 0 Then Exit Sub

            Dim tmp As ActorAction
            Dim i As Integer
            Do Until ActionQueue.Count = i

                tmp = ActionQueue(i)
                If tmp.humanim = EvoLib.Protocol.HUMAnimation.Walking Or tmp.humanim = EvoLib.Protocol.HUMAnimation.Running Or tmp.humanim = EvoLib.Protocol.HUMAnimation.Standing Then
                    ActionQueue.RemoveAt(i)
                Else
                    i += 1
                End If

            Loop
        End Sub

        Private Sub ClearAttacks()

            If ActionQueue.Count = 0 Then Exit Sub

            Dim tmp As ActorAction
            Dim i As Integer
            Do Until ActionQueue.Count = i

                tmp = ActionQueue(i)
                If tmp.humanim = EvoLib.Protocol.HUMAnimation.Attack Or tmp.humanim = EvoLib.Protocol.HUMAnimation.Cast1 Then
                    ActionQueue.RemoveAt(i)
                Else
                    i += 1
                End If

            Loop
        End Sub

        'TODO: Check this (could be that bug u just found)

        Public Sub ChangeMovementDirection(ByRef dir As EvoLib.Protocol.Direction)

            'If ActionQueue.Count = 1 And actualdirection <> dir Then

            Dim tmp As ActorAction
            tmp.dir = dir
            tmp.humanim = currentanim
            'currentmovementdirection = dir
            currentstaticdirection = dir

            'isAnimSet = False
            'startframe = mPlayerHumAnim.CurrentImg - mPlayerHumAnim.mCurrentAnim.mStartImg
            'If currentanim <> EvoLib.Protocol.HUMAnimation.Walking Then DeleteExcessActions(EvoLib.Protocol.mProtocol.HUMAnimation.Walking)
            'If currentanim <> EvoLib.Protocol.HUMAnimation.Running Then DeleteExcessActions(EvoLib.Protocol.mProtocol.HUMAnimation.Running)
            'If currentanim <> EvoLib.Protocol.HUMAnimation.Standing Then DeleteExcessActions(EvoLib.Protocol.mProtocol.HUMAnimation.Standing)
            ActionQueue.Add(tmp)

            'End If

        End Sub

        Public Sub ChangeStaticDirection(ByRef dir As EvoLib.Protocol.Direction)
            currentstaticdirection = dir
        End Sub

        Public Sub DoMove()

            Static lastanim As EvoLib.Protocol.HUMAnimation
            Static lastdir As EvoLib.Protocol.Direction

            If CInt(Me.MovementOffsetX) = 0 And CInt(Me.MovementOffsetY) = 0 And (lastxcoord <> mXCoord Or lastycoord <> mYCoord) Then

            Else

                If (currentmovementdistx = 0.0F And currentmovementdisty = 0.0F) Then
                Else

                    If currentmovementtimer + currentmovementtick <= DateTime.Now.Ticks Then

                        hasmoved = True

                        currentmovementtimer += currentmovementtick

                        Select Case actualdirection
                            Case EvoLib.Protocol.Direction.N
                                Me.MovementOffsetY += currentmovementdisty
                            Case EvoLib.Protocol.Direction.NE
                                Me.MovementOffsetY += currentmovementdisty
                                Me.MovementOffsetX -= currentmovementdistx
                            Case EvoLib.Protocol.Direction.E
                                Me.MovementOffsetX -= currentmovementdistx
                            Case EvoLib.Protocol.Direction.SE
                                Me.MovementOffsetY -= currentmovementdisty
                                Me.MovementOffsetX -= currentmovementdistx
                            Case EvoLib.Protocol.Direction.S
                                Me.MovementOffsetY -= currentmovementdisty
                            Case EvoLib.Protocol.Direction.SW
                                Me.MovementOffsetY -= currentmovementdisty
                                Me.MovementOffsetX += currentmovementdistx
                            Case EvoLib.Protocol.Direction.W
                                Me.MovementOffsetX += currentmovementdistx
                            Case EvoLib.Protocol.Direction.NW
                                Me.MovementOffsetY += currentmovementdisty
                                Me.MovementOffsetX += currentmovementdistx
                        End Select

                        If CInt(Me.MovementOffsetX) >= Constants.TileWidth \ 2 Then
                            Me.mXCoord -= 1
                            Me.MovementOffsetX = -(Constants.TileWidth - CInt(Me.MovementOffsetX))
                        ElseIf CInt(Me.MovementOffsetX) <= -Constants.TileWidth \ 2 Then
                            Me.mXCoord += 1
                            Me.MovementOffsetX = CInt(Me.MovementOffsetX) + Constants.TileWidth
                        End If
                        If CInt(Me.MovementOffsetY) >= Constants.TileHeight \ 2 Then
                            Me.mYCoord -= 1
                            Me.MovementOffsetY = -(Constants.TileHeight - CInt(Me.MovementOffsetY))
                        ElseIf CInt(Me.MovementOffsetY) <= -Constants.TileHeight \ 2 Then
                            Me.mYCoord += 1
                            Me.MovementOffsetY = CInt(Me.MovementOffsetY) + Constants.TileHeight
                        End If

                    End If
                End If

            End If

            CalcAnim()


            If CInt(MovementOffsetX) = 0 And CInt(MovementOffsetY) = 0 And (lastanim <> currentanim Or lastdir <> actualdirection Or lastxcoord <> mXCoord Or lastycoord <> mYCoord) Then
                lastanim = currentanim
                lastdir = actualdirection
                lastxcoord = mXCoord
                lastycoord = mYCoord
            End If

        End Sub

        Public Sub CalcAnim(Optional ByVal overidecentrelock As Boolean = False, Optional ByVal overrideanimlock As Boolean = False)

            Dim tmphumanim As GUI.Animation = Nothing
            Dim tmpheadanim As GUI.Animation = Nothing
            Dim tmpweapanim As GUI.Animation = Nothing
            Dim bLoop As Boolean = True

            Dim tmp As ActorAction
            Dim prevaction As EvoLib.Protocol.HUMAnimation = LastAction.humanim

            If ActionQueue.Count = 0 And Not overrideanimlock Then
                Stand()
                Exit Sub
            Else
                tmp = ActionQueue.Item(0)
                If tmp.humanim = EvoLib.Protocol.mProtocol.HUMAnimation.GettingHit And LastAction.humanim = EvoLib.Protocol.mProtocol.HUMAnimation.GettingHit And startframe = EvoLib.Protocol.HUMAnimationCounts(EvoLib.Protocol.HUMAnimation.GettingHit) - 1 Then
                    ActionQueue.Clear()
                    Dim info As PlayerPositionInfo
                    info.INT2_X = mXCoord
                    info.INT2_Y = mYCoord
                    Stand()
                    CalcAnim()
                    Exit Sub
                Else
                    LastAction = tmp
                End If
            End If


            'avoid freeze on hitting etc, add single use anims (casts like thing to this)
            Select Case tmp.humanim

                Case HUMAnimation.Attack, HUMAnimation.GettingHit, HUMAnimation.Cast1, HUMAnimation.Cast2
                    overrideanimlock = True


            End Select

            Application.DoEvents()

            If (tmp.humanim <> currentanim Or tmp.dir <> actualdirection Or lastxcoord <> mXCoord Or lastycoord <> mYCoord) Or overrideanimlock Then

                If ((CInt(Me.MovementOffsetX) = 0 And CInt(Me.MovementOffsetY) = 0)) Or currentanim = EvoLib.Protocol.HUMAnimation.GettingHit Or overrideanimlock Then

                    If isWalking Or isRunning Or overrideanimlock Then startframe = mHumAnim.CurrentImg - mHumAnim.mCurrentAnim.mStartImg

                    If tmp.humanim = EvoLib.Protocol.HUMAnimation.Walking Then

                        If mStepsToGo = 0 Then
                            'Stand()
                            'Exit Sub
                        End If

                        If mStepsToGo > 0 Then mStepsToGo -= 1

                        actualdirection = tmp.dir
                        Application.DoEvents()

                        tmphumanim = GetActorHumAnim(EvoLib.Protocol.HUMAnimation.Walking)
                        isRunning = False


                    ElseIf tmp.humanim = EvoLib.Protocol.HUMAnimation.Running Then

                        If mStepsToGo = 0 Then
                            'Stand()
                            'Exit Sub
                        End If

                        If mStepsToGo > 0 Then mStepsToGo -= 1

                        actualdirection = tmp.dir
                        Application.DoEvents()

                        If Not hasWalkedBeforeRun And Not isRunning Then

                            tmphumanim = GetActorHumAnim(EvoLib.Protocol.HUMAnimation.Walking)
                            bLoop = False
                            isRunning = True

                        Else

                            tmphumanim = GetActorHumAnim(EvoLib.Protocol.HUMAnimation.Running)

                            If Not hasRun Then
                                hasRun = True
                            End If

                            bLoop = True

                        End If

                    ElseIf tmp.humanim = EvoLib.Protocol.HUMAnimation.Attack Then

                        If currentanim = EvoLib.Protocol.HUMAnimation.Attack Then
                            DeleteExcessActions(EvoLib.Protocol.mProtocol.HUMAnimation.Attack, True)
                            If ActionQueue.Count = 0 Then
                                Stand()
                            End If
                        Else
                            actualdirection = tmp.dir
                            tmphumanim = GetActorHumAnim(EvoLib.Protocol.HUMAnimation.Attack)
                            bLoop = False
                            MovementOffsetY = 0
                            MovementOffsetX = 0
                        End If

                    ElseIf tmp.humanim = EvoLib.Protocol.HUMAnimation.Cast1 Then

                        If currentanim = EvoLib.Protocol.mProtocol.HUMAnimation.Cast1 Then
                            DeleteExcessActions(EvoLib.Protocol.mProtocol.HUMAnimation.Cast1, True)
                            If ActionQueue.Count = 0 Then
                                Stand()
                            End If
                        Else

                            actualdirection = tmp.dir
                            tmphumanim = GetActorHumAnim(EvoLib.Protocol.HUMAnimation.Cast1)
                            bLoop = False

                        End If

                    ElseIf tmp.humanim = EvoLib.Protocol.HUMAnimation.Die Then

                        actualdirection = tmp.dir
                        tmphumanim = GetActorHumAnim(EvoLib.Protocol.HUMAnimation.Die)
                        bLoop = False

                    ElseIf tmp.humanim = EvoLib.Protocol.HUMAnimation.GettingHit Then

                        If currentanim = EvoLib.Protocol.HUMAnimation.GettingHit Then
                            DeleteExcessActions(EvoLib.Protocol.mProtocol.HUMAnimation.GettingHit, True)
                            If ActionQueue.Count = 0 Then
                                Stand()
                            End If
                        Else
                            actualdirection = tmp.dir
                            tmphumanim = GetActorHumAnim(EvoLib.Protocol.HUMAnimation.GettingHit)
                            bLoop = False
                            MovementOffsetY = 0
                            MovementOffsetX = 0
                        End If

                    ElseIf tmp.humanim = EvoLib.Protocol.HUMAnimation.Standing Then

                        actualdirection = tmp.dir
                        tmphumanim = GetActorHumAnim(EvoLib.Protocol.HUMAnimation.Standing)
                        hasWalkedBeforeRun = False
                        bLoop = True
                        isRunning = False

                    End If

                End If

                If tmp.humanim = EvoLib.Protocol.HUMAnimation.GettingHit Then

                    'If startframe > 0 Then

                    'DeleteExcessActions(EvoLib.Protocol.mProtocol.HUMAnimation.GettingHit, True)
                    'Stand()
                    'isGettingHit = False
                    'CalcAnim()

                    Me.MovementOffsetX = 0.0F
                    Me.MovementOffsetY = 0.0F

                    If currentanim = EvoLib.Protocol.mProtocol.HUMAnimation.GettingHit Then
                        DeleteExcessActions(EvoLib.Protocol.mProtocol.HUMAnimation.GettingHit, True)
                        Stand()
                    End If
                    'Else

                    actualdirection = tmp.dir
                    tmphumanim = GetActorHumAnim(EvoLib.Protocol.HUMAnimation.GettingHit)
                    bLoop = False
                    hasWalkedBeforeRun = False
                    isRunning = False

                    'End If

                End If

                Application.DoEvents()

                If Not tmphumanim Is Nothing Then

                    If tmp.startpos.INT2_X <> 0 And CInt(Me.MovementOffsetX) = 0 And CInt(Me.MovementOffsetY) = 0 Then
                        mXCoord = tmp.startpos.INT2_X
                        mYCoord = tmp.startpos.INT2_Y
                    End If

                    If currentanim = EvoLib.Protocol.HUMAnimation.Running Or currentanim = EvoLib.Protocol.HUMAnimation.Walking Then

                        If prevaction = EvoLib.Protocol.HUMAnimation.Standing Then

                            Sound.PlaySoundEffect(Sound.GetSoundEffectFile(Sound.SoundEffects.StartWalking), 100)

                        Else

                            Sound.PlaySoundEffect(Sound.GetSoundEffectFile(Sound.SoundEffects.Walking), 100)

                        End If

                    ElseIf (prevaction = EvoLib.Protocol.HUMAnimation.Standing Or prevaction = EvoLib.Protocol.HUMAnimation.Running) And currentanim = EvoLib.Protocol.HUMAnimation.Walking Then

                        Sound.PlaySoundEffect(Sound.GetSoundEffectFile(Sound.SoundEffects.StopWalking), 100)

                    End If

                    mHumAnim.StartAnim(tmphumanim, bLoop, ShapeInfo.INT_ARMORCOL, startframe)

                    tmpheadanim = GetActorHeadAnim()
                    mHeadAnim.StartAnim(tmpheadanim, bLoop, ShapeInfo.INT_HAIRCOL, startframe)

                    'If Not isMounted Then
                    tmpweapanim = GetActorWeaponAnim()
                    mWeaponAnim.StartAnim(tmpweapanim, bLoop, , startframe)
                    mWeaponAnim.Visible = True
                    'Else
                    'mWeaponAnim.Visible = False
                    'End If


                    startframe = 0

                End If

            End If

        End Sub

        Private Function GetActorHumAnim(ByRef anim As EvoLib.Protocol.HUMAnimation) As GUI.Animation

            currentmovementtick = EvoLib.Protocol.HUMAnimationMoveTick(anim)

            If IsOverencumbered(Stats, Weights) Then

                currentmovementtick = currentmovementtick * Constants.OverencumberedFactor

            End If

            currentmovementtimer = DateTime.Now.Ticks
            currentmovementdistx = EvoLib.Protocol.HUMAnimationDistanceX(anim)
            currentmovementdisty = EvoLib.Protocol.HUMAnimationDistanceY(anim)
            currentanim = anim

            Dim tmp As Libs.LibShapePair = Libs.GetArmourLib(ActorSex, ShapeInfo.INT_ARMORSHAPE)
            Return New GUI.Animation(tmp.library, (tmp.shape * 3000) + 1 + (anim * 80) + (actualdirection * 10), EvoLib.Protocol.HUMAnimationCounts(anim), EvoLib.Protocol.HUMAnimationTick(anim))

        End Function

        Private Function GetActorHeadAnim() As GUI.Animation

            If ShapeInfo.INT_HEADSHAPE = 22 And Not ShapeInfo.BOOL_HEADISHELM Then
                Return Nothing
            Else

                Dim tmp As Libs.LibShapePair
                If ShapeInfo.BOOL_HEADISHELM And ShapeInfo.INT_HEADSHAPE >= 0 Then
                    tmp = Libs.GetHeadLib(ActorSex, ShapeInfo.INT_HEADSHAPE, ShapeInfo.BOOL_HEADISHELM)
                Else
                    tmp = Libs.GetHeadLib(ActorSex, ShapeInfo.INT_HAIRSHAPE, False)
                End If

                If Weights.INT4_BAGWEIGHT > Stats.INT2_MAX_WEIGHT Then
                    Return New GUI.Animation(tmp.library, (tmp.shape * 3000) + 1 + (currentanim * 80) + (actualdirection * 10), EvoLib.Protocol.HUMAnimationCounts(currentanim), EvoLib.Protocol.HUMAnimationTick(currentanim) * Constants.OverencumberedFactor)
                Else
                    Return New GUI.Animation(tmp.library, (tmp.shape * 3000) + 1 + (currentanim * 80) + (actualdirection * 10), EvoLib.Protocol.HUMAnimationCounts(currentanim), EvoLib.Protocol.HUMAnimationTick(currentanim))
                End If

            End If

        End Function

        Private Function GetActorWeaponAnim() As GUI.Animation

            If ShapeInfo.INT_WEAPONSHAPE = -1 Then Return Nothing

            Dim tmp As Libs.LibShapePair = Libs.GetWeaponLib(ActorSex, ShapeInfo.INT_WEAPONSHAPE)

            If Weights.INT4_BAGWEIGHT > Stats.INT2_MAX_WEIGHT Then
                Return New GUI.Animation(tmp.library, (tmp.shape * 3000) + 1 + (currentanim * 80) + (actualdirection * 10), EvoLib.Protocol.HUMAnimationCounts(currentanim), EvoLib.Protocol.HUMAnimationTick(currentanim) * Constants.OverencumberedFactor)
            Else
                Return New GUI.Animation(tmp.library, (tmp.shape * 3000) + 1 + (currentanim * 80) + (actualdirection * 10), EvoLib.Protocol.HUMAnimationCounts(currentanim), EvoLib.Protocol.HUMAnimationTick(currentanim))
            End If

        End Function


        Public Function CalcNextStep(ByVal cx As Integer, ByVal cy As Integer, ByVal dir As EvoLib.Protocol.Direction) As Point

            Dim ret As New Point(cx, cy)

            Select Case dir
                Case EvoLib.Protocol.Direction.N
                    ret.Y -= 1
                Case EvoLib.Protocol.Direction.NE
                    ret.Y -= 1
                    ret.X += 1
                Case EvoLib.Protocol.Direction.E
                    ret.X += 1
                Case EvoLib.Protocol.Direction.SE
                    ret.Y += 1
                    ret.X += 1
                Case EvoLib.Protocol.Direction.S
                    ret.Y += 1
                Case EvoLib.Protocol.Direction.SW
                    ret.Y += 1
                    ret.X -= 1
                Case EvoLib.Protocol.Direction.W
                    ret.X -= 1
                Case EvoLib.Protocol.Direction.NW
                    ret.Y -= 1
                    ret.X -= 1
            End Select

            Return ret

        End Function

        Private Sub mPlayerHumAnim_AnimStopped() Handles mHumAnim.AnimStopped

            isGettingHit = False

            Dim tmp As EvoLib.Protocol.PlayerPositionInfo
            tmp.INT2_X = mXCoord
            tmp.INT2_Y = mYCoord

            If currentanim = EvoLib.Protocol.HUMAnimation.Walking Then

                hasWalkedBeforeRun = True
                CalcAnim()

                'ElseIf isCasting1 Then
                'ResetAnimBools()
                'Stand()
                'CalcAnim()
                'ElseIf isAttacking Then
                'ResetAnimBools()
                'Stand()
                'CalcAnim()

            ElseIf currentanim = EvoLib.Protocol.HUMAnimation.GettingHit Then

                If ActionQueue.Count > 0 Then ActionQueue.RemoveAt(0)
                Stand()
                CalcAnim()

                'If ActionQueue.Count > 1 Then ActionQueue.RemoveAt(0)
            ElseIf currentanim = EvoLib.Protocol.HUMAnimation.Die Then

                ActionQueue.Clear()

            Else

                ActionQueue.RemoveAt(0)
                Stand()
                CalcAnim()

            End If

        End Sub

        Public Sub ChatMessage(ByRef msg As EvoLib.Protocol.CharChatMsg)

            'set chat text
            mChatText = msg.STR_NAME & ": " & msg.msg.STR_MSG
            'set display timeout
            mChatTimeout = DateTime.Now.Ticks + Constants.ChatMessageDisplayTime

        End Sub

        Private Sub DeleteExcessActions(ByVal anim As EvoLib.Protocol.HUMAnimation, Optional ByVal deleteall As Boolean = False)

            SyncLock objAnimLock


                Dim foundfirstentry As Boolean
                Dim i As Integer = ActionQueue.Count - 1

                Do Until i = 0

                    If ActionQueue(i).humanim = anim Then

                        If deleteall Then
                            ActionQueue.RemoveAt(i)
                        Else
                            If foundfirstentry Then
                                ActionQueue.RemoveAt(i)
                            Else
                                foundfirstentry = True
                            End If
                        End If

                    End If

                    i -= 1

                Loop

            End SyncLock

        End Sub

        Private Sub mHumAnim_MouseEvent(ByRef type As Mouse.MouseInputType, ByRef e As MouseEventArgs, name As String) Handles mHumAnim.MouseEvent

            Mouse.MouseOverPlayerID = Me.ActorID

        End Sub

        Private Sub mHeadAnim_MouseEvent(ByRef type As Mouse.MouseInputType, ByRef e As MouseEventArgs, name As String) Handles mHeadAnim.MouseEvent

            Call mHumAnim_MouseEvent(type, e, name)

        End Sub

        Private Sub mWeaponAnim_MouseEvent(ByRef type As Mouse.MouseInputType, ByRef e As MouseEventArgs, name As String) Handles mWeaponAnim.MouseEvent

            Call mHumAnim_MouseEvent(type, e, name)

        End Sub
    End Class


End Namespace